//
// Created by 86155 on 2025/4/16.
//

#include "FeRegisterInfo.h"
#include "Fe.h"
#include "MCTargetDesc/FeMCTargetDesc.h"
#include "FeSubtarget.h"

#include "llvm/CodeGen/MachineFrameInfo.h"
using namespace llvm;

#define GET_REGINFO_TARGET_DESC
#include "FeGenRegisterInfo.inc"

#define DEBUG_TYPE "fe register info"

//必须传返回寄存器X1
FeRegisterInfo::FeRegisterInfo(const FeSubtarget &STI)
    : FeGenRegisterInfo(Fe::RA), STI(STI) {}

const MCPhysReg *
FeRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
  return CSR_SaveList;
}

BitVector FeRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  BitVector Reserved(getNumRegs()); //多少个寄存器就有多少个bit
  Reserved.set(Fe::ZERO);
  Reserved.set(Fe::RA);
  Reserved.set(Fe::SP);
  return Reserved;
}

bool FeRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                          int SPAdj, unsigned FIOperandNum,
                                          RegScavenger *RS) const {
  MachineInstr &MI = *II;
  LLVM_DEBUG(errs() << MI);

  /// MI (Reg, FrameIndex, IMM)

  uint I = 0;
  while (!MI.getOperand(I).isFI()) {
    ++I;
    assert(I < MI.getNumOperands());
  }

  const int FI = MI.getOperand(I).getIndex();

  /// 根据 index -> 函数栈帧内部的偏移量
  const MachineFunction &MF = *MI.getParent()->getParent();
  const MachineFrameInfo &MFI = MF.getFrameInfo();
  /// Offset 是基于栈基地址的，是一个负数
  /// 我们要变成基于栈顶的，因此sp + (一个正数)
  int64_t Offset = MFI.getObjectOffset(FI);
  uint64_t STACKSIZE =
      ROUND_UP(MFI.getStackSize(), STI.getFrameLowering()->getStackAlignment());
  /// 回到栈顶
  Offset += static_cast<int64_t>(STACKSIZE);

  /// 栈内偏移
  Offset += MI.getOperand(I+1).getImm();

  MI.getOperand(I).ChangeToRegister(Fe::SP, false);
  MI.getOperand(I + 1).ChangeToImmediate(Offset);
  // MI.getOperand(I + 1).setImm(Offset);
  return true;
}

const uint32_t *FeRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
                                                      CallingConv::ID) const {
  return CSR_RegMask;
}

Register
FeRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
  return Fe::SP;
}